package main

import (
	"flag"
	"fmt"
	"html/template"
	"io"
	"net"
	"net/http"
	"os"
	"strings"
)

const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Go 文件服务器</title>
</head>
<body>
	<h1>当前目录: {{.Path}}</h1>
	<form action="/__api__/upload" method="post" enctype="multipart/form-data">
		<input type="file" name="file">
		<input type="submit" value="上传">
	</form>
	<table border="1" cellpadding="5">
		<tr><th>名称</th><th>操作</th></tr>
		{{range .Files}}
		<tr>
			<td>{{.Name}}</td>
			<td>
				<a href="/files/{{.Name}}">下载</a> |
				<a href="/__api__/delete?name={{.Name}}">删除</a> |
				<form style="display:inline" action="/__api__/rename" method="post">
					<input type="hidden" name="old" value="{{.Name}}">
					<input type="text" name="new" placeholder="新名称">
					<input type="submit" value="重命名">
				</form>
			</td>
		</tr>
		{{end}}
	</table>
</body>
</html>
`

type FileInfo struct {
	Name string
}

type PageData struct {
	Path  string
	Files []FileInfo
}

func main() {

	// 设置端口参数，默认值为 80
	port := flag.Int("port", 80, "监听端口（默认: 80）")
	flag.Parse()
	addr := fmt.Sprintf(":%d", *port)

	// 页面与静态路由
	http.HandleFunc("/", handleList)
	http.HandleFunc("/files/", handleDirectDownload)

	// API 路由，统一使用 __api__ 前缀
	http.HandleFunc("/__api__/upload", handleUpload)
	http.HandleFunc("/__api__/delete", handleDelete)
	http.HandleFunc("/__api__/rename", handleRename)

	localIP := getLocalIP()

	fmt.Printf("文件服务器已启动：\n")
	fmt.Printf(" - 本机地址：http://%s:%d/\n", localIP, *port)
	fmt.Printf(" - 请通过以上地址或其他能够访问本机的地址访问")
	http.ListenAndServe(addr, nil)
}

// 显示文件列表页面
func handleList(w http.ResponseWriter, r *http.Request) {
	files, err := os.ReadDir(".")
	if err != nil {
		http.Error(w, "读取目录失败", http.StatusInternalServerError)
		return
	}
	var fileInfos []FileInfo
	for _, f := range files {
		if !f.IsDir() {
			fileInfos = append(fileInfos, FileInfo{Name: f.Name()})
		}
	}
	tmpl := template.Must(template.New("page").Parse(htmlTemplate))
	tmpl.Execute(w, PageData{
		Path:  ".",
		Files: fileInfos,
	})
}

// 上传文件
func handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}
	file, header, err := r.FormFile("file")
	if err != nil {
		http.Error(w, "文件读取失败", http.StatusBadRequest)
		return
	}
	defer file.Close()

	dst, err := os.Create(header.Filename)
	if err != nil {
		http.Error(w, "文件保存失败", http.StatusInternalServerError)
		return
	}
	defer dst.Close()
	io.Copy(dst, file)

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

// 下载文件（支持 /files/filename 形式）
func handleDirectDownload(w http.ResponseWriter, r *http.Request) {
	filename := strings.TrimPrefix(r.URL.Path, "/files/")
	if filename == "" || strings.Contains(filename, "/") || strings.Contains(filename, "..") {
		http.Error(w, "非法文件名", http.StatusBadRequest)
		return
	}
	http.ServeFile(w, r, filename)
}

// 删除文件
func handleDelete(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get("name")
	if name == "" {
		http.Error(w, "文件名不能为空", http.StatusBadRequest)
		return
	}
	err := os.Remove(name)
	if err != nil {
		http.Error(w, "删除失败: "+err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/", http.StatusSeeOther)
}

// 重命名文件
func handleRename(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}
	oldName := r.FormValue("old")
	newName := r.FormValue("new")
	if oldName == "" || newName == "" {
		http.Error(w, "文件名不能为空", http.StatusBadRequest)
		return
	}
	// 防止路径穿越
	if strings.Contains(newName, "/") || strings.Contains(newName, "..") {
		http.Error(w, "新名称非法", http.StatusBadRequest)
		return
	}
	err := os.Rename(oldName, newName)
	if err != nil {
		http.Error(w, "重命名失败: "+err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/", http.StatusSeeOther)
}

// 获取首个非回环、非虚拟接口的 IPv4 地址
func getLocalIP() string {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "localhost"
	}

	for _, iface := range ifaces {
		// 跳过未启用或回环接口
		if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
			continue
		}
		// 跳过常见的虚拟接口
		if strings.Contains(iface.Name, "docker") || strings.Contains(iface.Name, "vm") || strings.Contains(iface.Name, "tun") {
			continue
		}

		addrs, _ := iface.Addrs()
		for _, addr := range addrs {
			if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil {
				return ipNet.IP.String()
			}
		}
	}
	return "localhost"
}
